//
//  UIImage+Handle.m
//  XLProject
//
//  Created by xinglian on 2021/9/7.
//

#import "UIImage+Handle.h"

//全局内存空间地址指针 用于在合适的时候释放内存
void * bitmap;


#define RGB888_RED      0x00ff0000
#define RGB888_GREEN    0x0000ff00
#define RGB888_BLUE     0x000000ff


# pragma pack(push, 1)
typedef struct s_bitmap_header
{
    // Bitmap file header
    UInt16 fileType;
    UInt32 fileSize;
    UInt16 reserved1;
    UInt16 reserved2;
    UInt32 bitmapOffset;
    
    // DIB Header
    UInt32 headerSize;
    UInt32 width;
    UInt32 height;
    UInt16 colorPlanes;
    UInt16 bitsPerPixel;
    UInt32 compression;
    UInt32 bitmapSize;
    UInt32 horizontalResolution;
    UInt32 verticalResolution;
    UInt32 colorsUsed;
    UInt32 colorsImportant;
} t_bitmap_header;
//#pragma pack(pop)






// 改变一个byte里面某个bit的值.
UInt8 bitInsertInt(UInt8 val, int position, bool value)
{
    if (value) {
        UInt8 tmp = (value << position);
        val = val | tmp;
    } else {
        UInt8 tmp = ~(!value << position);
        val = val & tmp;
    }
    
    return val;
}

// 从某个int里面取出position位置bit的值.
bool intConvertBit(int val, int position)
{
    val = val >> position;
    return val % 2;
}





@implementation UIImage (Handle)





- (NSData *)bitmapData2
{
    NSData          *bitmapData = nil;
    CGImageRef      image = self.CGImage;
    CGContextRef    context = NULL;
    CGColorSpaceRef colorSpace;
    UInt8           *rawData;
    
    size_t bitsPerPixel = 32;
    size_t bitsPerComponent = 8;
    size_t bytesPerPixel = bitsPerPixel / bitsPerComponent;
    
    size_t width = 360;
    size_t height = 360;
    
    size_t bytesPerRow = width * bytesPerPixel;
    size_t bufferLength = bytesPerRow * height;
    
    colorSpace = CGColorSpaceCreateDeviceRGB();
    
    if (colorSpace)
    {
        // Allocate memory for raw image data
        rawData = (UInt8 *)calloc(bufferLength, sizeof(UInt8));
        NSLog(@"---%lu", sizeof(rawData));
        if (rawData)
        {
            CGBitmapInfo bitmapInfo = kCGImageByteOrder32Little | kCGImageAlphaPremultipliedFirst;
            context = CGBitmapContextCreate(rawData,
                                            width,
                                            height,
                                            8,
                                            bytesPerRow,
                                            colorSpace,
                                            bitmapInfo);
            
            if (context)
            {
                CGRect rect = CGRectMake(0, 0, width, height);
                
                CGContextTranslateCTM(context, 0, height);
                CGContextScaleCTM(context, 1.0, -1.0);
                CGContextDrawImage(context, rect, image);
                
                bitmapData = [NSData dataWithBytes:rawData length:bufferLength];
                CGContextRelease(context);
            }
            
            free(rawData);
        }
        
        CGColorSpaceRelease(colorSpace);
    }
    
    return bitmapData;
}






- (NSData *)bitmapData
{
    NSData          *bitmapData = nil;
    CGImageRef      image = self.CGImage;
    CGContextRef    context = NULL;
    CGColorSpaceRef colorSpace;
    
    size_t width = 360;
    size_t height = 360;
    
    colorSpace = CGColorSpaceCreateDeviceRGB();
    
    CGBitmapInfo bitmapInfo = kCGImageByteOrderDefault | kCGImageAlphaPremultipliedLast;

    context = CGBitmapContextCreate(NULL,
                                    width,
                                    height,
                                    8,
                                    0,
                                    colorSpace,
                                    bitmapInfo);
    
    
    if (context)
    {
        CGRect rect = CGRectMake(0, 0, width, height);
        
        CGContextTranslateCTM(context, 0, height);
        CGContextScaleCTM(context, 1.0, -1.0);
        CGContextDrawImage(context, rect, image);
        
//        bitmapData = [NSData dataWithBytes:rawData length:259200];
        CGImageRef cfImg = CGBitmapContextCreateImage(context);
        bitmapData = UIImagePNGRepresentation([UIImage imageWithCGImage:cfImg]);
//        bitmapData = CGBitmapContextGetData(context);
        
        CGContextRelease(context);
    }
    
    
    CGColorSpaceRelease(colorSpace);
    return bitmapData;
}








+ (NSData *) newBitmapRGBA8ContextFromImage:(CGImageRef) image {
    CGContextRef context = NULL;
    CGColorSpaceRef colorSpace;
    uint32_t *bitmapData;

    size_t bitsPerPixel = 16;
    size_t bitsPerComponent = 8;
    size_t bytesPerPixel = bitsPerPixel / bitsPerComponent;

    size_t width = 360;
    size_t height = 360;

    size_t bytesPerRow = width * bytesPerPixel;
    size_t bufferLength = bytesPerRow * height;

    colorSpace = CGColorSpaceCreateDeviceRGB();

    if(!colorSpace) {
        NSLog(@"Error allocating color space RGB\n");
        return NULL;
    }

    // Allocate memory for image data
    bitmapData = (uint32_t *)malloc(bufferLength);

    if(!bitmapData) {
        NSLog(@"Error allocating memory for bitmap\n");
        CGColorSpaceRelease(colorSpace);
        return NULL;
    }

    //Create bitmap context

    context = CGBitmapContextCreate(bitmapData,
            width,
            height,
            bitsPerComponent,
            bytesPerRow,
            colorSpace,
            kCGImageAlphaPremultipliedLast);    // RGBA
    if(!context) {
        free(bitmapData);
        NSLog(@"Bitmap context not created");
    }

    CGColorSpaceRelease(colorSpace);
    
    CGImageRef imageRef = CGBitmapContextCreateImage(context);
    UIImage *returnImage = [UIImage imageWithCGImage:imageRef];
    
    return UIImagePNGRepresentation(returnImage);
}






- (NSData *)bitmapFileHeaderData
{
    CGImageRef image = self.CGImage;
    UInt32     width = (UInt32)CGImageGetWidth(image);
    UInt32     height = (UInt32)CGImageGetHeight(image);
    
    t_bitmap_header header;
    header.fileType = 0x4D42;
    header.fileSize = (height * width * 3) + 54;
    header.reserved1 = 0x0000;
    header.reserved2 = 0x0000;
    header.bitmapOffset = 0x00000036;
    header.headerSize = 0x00000028;
    header.width = width;
    header.height = height;
    header.colorPlanes = 0x0001;
    header.bitsPerPixel = 0x0018;
    header.compression = 0x00000000;
    header.bitmapSize = width * height * 3;
    header.horizontalResolution = 0x00000000;
    header.verticalResolution = 0x00000000;
    header.colorsUsed = 0x00000000;
    header.colorsImportant = 0x00000000;
    
    return [NSData dataWithBytes:&header length:sizeof(t_bitmap_header)];
}

- (NSData *)bitmapDataWithFileHeader
{
    NSMutableData *data = [NSMutableData dataWithData:[self bitmapFileHeaderData]];
    [data appendData:[self bitmapData]];
    
    return [NSData dataWithData:data];
}











/**
 *  从图片中按指定的位置大小截取图片的一部分
 *
 *  @param image UIImage image 原始的图片
 *  @param rect  CGRect rect 要截取的区域
 *
 *  @return UIImage
 */
+ (UIImage *)ct_imageFromImage:(UIImage *)image inRect:(CGRect)rect{
    
    //把像 素rect 转化为 点rect（如无转化则按原图像素取部分图片）
    CGFloat scale = [UIScreen mainScreen].scale;
    CGFloat x= rect.origin.x*scale,y=rect.origin.y*scale,w=rect.size.width*scale,h=rect.size.height*scale;
    CGRect dianRect = CGRectMake(x, y, w, h);

    //截取部分图片并生成新图片
    CGImageRef sourceImageRef = [image CGImage];
    CGImageRef newImageRef = CGImageCreateWithImageInRect(sourceImageRef, dianRect);
    UIImage *newImage = [UIImage imageWithCGImage:newImageRef scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp];
    return newImage;
}







+ (UIImage *)imageWithMaxSide:(CGFloat)length sourceImage:(UIImage *)image{
    
    CGFloat scale = [[UIScreen mainScreen] scale];
    CGSize imgSize = SizeReduce(image.size, length);
    UIImage *img = nil;

    UIGraphicsBeginImageContextWithOptions(imgSize, YES, scale);  // 创建一个 bitmap context

    [image drawInRect:CGRectMake(0, 0, imgSize.width, imgSize.height)
            blendMode:kCGBlendModeNormal alpha:1.0];              // 将图片绘制到当前的 context 上

    img = UIGraphicsGetImageFromCurrentImageContext();            // 从当前 context 中获取刚绘制的图片
    UIGraphicsEndImageContext();

    return img;
}




static inline
CGSize SizeReduce(CGSize size, CGFloat limit)   // 按比例减少尺寸
{
    CGFloat max = MAX(size.width, size.height);
    if (max < limit) {
        return size;
    }

    CGSize imgSize;
    CGFloat ratio = size.height / size.width;

    if (size.width > size.height) {
        imgSize = CGSizeMake(limit, limit*ratio);
    } else {
        imgSize = CGSizeMake(limit/ratio, limit);
    }

    return imgSize;
}






/**
 *  调整图片尺寸和大小
 *
 *  @param sourceImage  原始图片
 *  @param maxImageSize 新图片最大尺寸
 *  @param maxSize      新图片最大存储大小
 *
 *  @return 新图片imageData
 */
+ (NSData *)reSizeImageData:(UIImage *)sourceImage maxImageSize:(CGFloat)maxImageSize maxSizeWithKB:(CGFloat) maxSize
{

    if (maxSize <= 0.0) maxSize = 1024.0;
    if (maxImageSize <= 0.0) maxImageSize = 1024.0;
    
    //先调整分辨率
    CGSize newSize = CGSizeMake(sourceImage.size.width, sourceImage.size.height);
    
    CGFloat tempHeight = newSize.height / maxImageSize;
    CGFloat tempWidth = newSize.width / maxImageSize;
    
    if (tempWidth > 1.0 && tempWidth > tempHeight) {
        newSize = CGSizeMake(sourceImage.size.width / tempWidth, sourceImage.size.height / tempWidth);
    }
    else if (tempHeight > 1.0 && tempWidth < tempHeight){
        newSize = CGSizeMake(sourceImage.size.width / tempHeight, sourceImage.size.height / tempHeight);
    }
    
    UIGraphicsBeginImageContext(newSize);
    [sourceImage drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    //调整大小
    NSData *imageData = UIImageJPEGRepresentation(newImage,1.0);
    CGFloat sizeOriginKB = imageData.length / 1024.0;
    
    CGFloat resizeRate = 0.9;
    while (sizeOriginKB > maxSize && resizeRate > 0.1) {
        imageData = UIImageJPEGRepresentation(newImage,resizeRate);
        sizeOriginKB = imageData.length / 1024.0;
        resizeRate -= 0.1;
    }
    
    return imageData;
}














#pragma mark ---

- (NSData *)createImageDataWithImage:(UIImage *)inImage writetype:(NSInteger)type
{

    /*        图片位图像素值数组         */
    unsigned char *imgPixel = RequestImagePixelData(inImage);
    
    CGImageRef inImageRef = [inImage CGImage];
    long w = CGImageGetWidth(inImageRef);
    long h = CGImageGetHeight(inImageRef);
    
    int wOff = 0;
    int pixOff = 0;
    /*        遍历修改位图像素值         */
    NSInteger count = 0;
    NSMutableData *dataArray = [NSMutableData data];
    for (long y = 0; y<h; y++) {
        pixOff = wOff;
        for (long x = 0; x<w; x++) {
            int alpha = (unsigned char)imgPixel[pixOff +3];
            UInt16 red = (unsigned char)imgPixel[pixOff+2];
            UInt16 green = (unsigned char)imgPixel[pixOff+1];
            UInt16 blue = (unsigned char)imgPixel[pixOff +0];

//           UInt16 byteChar = ((red&0xff >>3) <<11) + ((green&0xff >> 2)<<5) + (blue&0xff >> 3);
            UInt16 byteChar = (((red << 8) & 0xF800)|((green << 3) & 0x7E0)|(blue >> 3));

            Byte ByteData[2];
            ByteData[0] = (byteChar & 0xff00) >> 8;
            ByteData[1] = byteChar & 0xff;
            NSData *data2 = [NSData dataWithBytes:ByteData length:2];
            
            [dataArray appendData:data2];
            pixOff += 4;
//            NSLog(@"R:%d G:%d B:%d A:%d",red,green,blue,alpha);
            count++;
        }
        wOff += w * 4 ;
    }
        NSLog(@"宽度>>>%d 高度>>>%d 总>>>%d 总的:rgb点数>>>%d",w,h,w*h,count);
//    NSLog(@"dataArray.count>>>%d",dataArray.length);
    return  dataArray;
}




//返回一个指针，该指针指向一个数组，数组中的每四个元素都是图像上的一个像素点的RGBA的数值（0-255），用无符号的char是因为它正好的取值范围就是0-255
static unsigned char *RequestImagePixelData(UIImage * inImage){
    CGImageRef img = [inImage CGImage];
    CGSize size = [inImage size];
    //使用上面的函数创建上下文
    CGContextRef cgctx = CreateRGBABitmapContex(img);
    CGRect rect = {{0,0},{size.width,size.height}};
    
    //将目标图像绘制到指定的上下文，实际为上下文内的bitmapData。
    CGContextDrawImage(cgctx, rect, img);
    unsigned char *data = CGBitmapContextGetData(cgctx);

    //释放上面的函数创建的上下文
    CGContextRelease(cgctx);
    cgctx = NULL;

    return data;
}





static CGContextRef CreateRGBABitmapContex(CGImageRef inImage){
    
    CGContextRef context = NULL;
    /*        颜色通道         */
    CGColorSpaceRef colorSpace;
    void *bitmapData;//内存空间的指针，该内存空间的大小等于图像使用RGB通道所占用的字节数。
    long bitmapByteCount;
    long bitmapBytePerRow;
    
    /*        获取像素的横向和纵向个数         */
    size_t pixelsWith = CGImageGetWidth(inImage);
    size_t pixelsHigh = CGImageGetHeight(inImage);

    /*        每一行的像素点占用的字节数，每个像素点的RGBA四个通道各占8bit空间         */
    bitmapBytePerRow = (pixelsWith * 4);
    
    /*       整张图片占用的字节数          */
    bitmapByteCount = (bitmapBytePerRow * pixelsHigh);
    
    /*        创建依赖设备的RGB通道         */
    colorSpace = CGColorSpaceCreateDeviceRGB();
    
    /*        分配足够容纳图片字节数的内存空间         */
    bitmapData = malloc(bitmapByteCount);
    
    bitmap = bitmapData;
    
    /*        创建CoreGraphic的图形上下文 该上下文描述了bitmaData指向的内存空间需要绘制的图像的一些绘制参数         */
    
    context = CGBitmapContextCreate(bitmapData,
                                    pixelsWith,
                                    pixelsHigh,
                                    8,
                                    bitmapBytePerRow,
                                    colorSpace,
                                    CGImageGetBitmapInfo(inImage));
    
    /*        Core Foundation中含有Create、Alloc的方法名字创建的指针，需要使用CFRelease（）函数释放         */
    CGColorSpaceRelease(colorSpace);
    
    if (bitmapData == NULL) {
        return NULL;
    }

    return context;
    
}








@end
